package cn.iocoder.yudao.module.system.controller.admin.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.ids.IdsService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.module.system.service.tenant.TenantPackageService;
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.obtainAuthorization;

@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {

    @Resource
    private AdminAuthService authService;
    @Resource
    private AdminUserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private SocialClientService socialClientService;

    @Resource
    private SecurityProperties securityProperties;

    @Resource
    private IdsService idsService;

    @Resource
    private TenantService tenantService;

    @Resource
    private TenantPackageService tenantPackageService;

    @PostMapping("/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO));
    }

    @PostMapping("/logout")
    @PermitAll
    @Operation(summary = "登出系统")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> logout(HttpServletRequest request) {
        String token = obtainAuthorization(request, securityProperties.getTokenHeader());
        if (StrUtil.isNotBlank(token)) {
            authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
        }
        return success(true);
    }

    @PostMapping("/refresh-token")
    @PermitAll
    @Operation(summary = "刷新令牌")
    @Parameter(name = "refreshToken", description = "刷新令牌", required = true)
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
        return success(authService.refreshToken(refreshToken));
    }

    @GetMapping("/get-permission-info")
    @Operation(summary = "获取登录用户的权限信息")
    public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
        // 1.1 获得用户信息
        AdminUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return null;
        }

        // 1.2 获得角色列表
        Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
        if (CollUtil.isEmpty(roleIds)) {
            return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
        }
        List<RoleDO> roles = roleService.getRoleList(roleIds);
        roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色

        // 1.3 获得菜单列表
        Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
        List<MenuDO> menuList = menuService.getMenuList(menuIds);
        menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单

        // 2. 拼接结果返回
        return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
    }

    // ========== 短信登录相关 ==========

    @PostMapping("/sms-login")
    @PermitAll
    @Operation(summary = "使用短信验证码登录")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
        return success(authService.smsLogin(reqVO));
    }

    @PostMapping("/send-sms-code")
    @PermitAll
    @Operation(summary = "发送手机验证码")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
        authService.sendSmsCode(reqVO);
        return success(true);
    }

    // ========== 社交登录相关 ==========

    @GetMapping("/social-auth-redirect")
    @PermitAll
    @Operation(summary = "社交授权的跳转")
    @Parameters({
            @Parameter(name = "type", description = "社交类型", required = true),
            @Parameter(name = "redirectUri", description = "回调路径")
    })
    public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
                                            @RequestParam("redirectUri") String redirectUri) {
        return success(socialClientService.getAuthorizeUrl(
                type, UserTypeEnum.ADMIN.getValue(), redirectUri));
    }

    @PostMapping("/social-login")
    @PermitAll
    @Operation(summary = "社交快捷登录，使用 code 授权码", description = "适合未登录的用户，但是社交账号已绑定用户")
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
        return success(authService.socialLogin(reqVO));
    }


    @GetMapping("/loginIDS")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<AuthLoginRespVO> loginIDS(HttpServletRequest req, HttpServletResponse res, @RequestParam("trsidsssosessionid") String trsidsssosessionid) {
        return success(idsService.loginIDS(req, res, trsidsssosessionid));
    }

   /* @GetMapping("/checkIdsLoginRedirect")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> idsLoginRedirect(HttpServletRequest req) {
        return success(idsService.checkIdsLoginRedirect(req));
    }*/

    @GetMapping("/checkIDSLogin")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> idsLoginRedirect(HttpServletRequest req, @RequestParam("trsidsssosessionid") String trsidsssosessionid) {
        if(StringUtils.isNotBlank(trsidsssosessionid) && !trsidsssosessionid.equals("null")) {
            return success(idsService.checkIDSLogin(req, trsidsssosessionid));
        }else{
            return success(true);
        }
    }

    @GetMapping("/getTenantName")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> getTenantName(HttpServletRequest req, @RequestParam("trsidsssosessionid") String trsidsssosessionid) {
        if(StringUtils.isNotBlank(trsidsssosessionid)) {
            return success(idsService.getTenantName(req, trsidsssosessionid));
        }else{
            return success("");
        }
    }


    @GetMapping("/loginRedirect")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> loginRedirect(HttpServletRequest request) {
        return success(idsService.loginRedirect(request));
    }


    @GetMapping("/logoutIds")
    @CrossOrigin
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> logoutIds(@RequestParam("trsidsssosessionid") String trsidsssosessionid) {
        return success(idsService.idsLogout(trsidsssosessionid));
    }


    @PostMapping("/addUser")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> addUser(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.addUser(req, res));
    }


    @PostMapping("/openUser")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> openUser(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.openUser(req, res));
    }


    @PostMapping("/updateUser")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> updateUser(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.updateUser(req, res));
    }


    @PostMapping("/closeUser")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> closeUser(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.closeUser(req, res));
    }


    @PostMapping("/deleteUser")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> deleteUser(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.deleteUser(req, res));
    }


    @PostMapping("/disOrgan")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> disOrgan(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.disOrgan(req, res));
    }


    @PostMapping("/removeOrgan")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> removeOrgan(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.removeOrgan(req, res));
    }


    @PostMapping("/addOrgan")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> addOrgan(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.addOrgan(req, res));
    }


    @PostMapping("/deleteOrgan")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> deleteOrgan(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.deleteOrgan(req, res));
    }


    @PostMapping("/updateOrgan")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<String> updateOrgan(HttpServletRequest req, HttpServletResponse res) {
        return success(idsService.updateOrgan(req, res));
    }


    @PostMapping("/createTenantByPortal")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Long> createTenantByPortal(@RequestBody IdsVo idsVo) {
        TenantCreateReqVO createReqVO = new TenantCreateReqVO();
        createReqVO.setUsername(idsVo.getTenantName() + "@superAdmin");
        createReqVO.setPassword("123456");
        createReqVO.setName(idsVo.getTenantName());
        createReqVO.setContactName("superAdmin");
        createReqVO.setStatus(0);
        createReqVO.setPackageId(113L);
        createReqVO.setExpireTime(DateUtil.format(idsVo.getExpireTime(),"yyyy-MM-dd HH:mm:ss"));
        createReqVO.setAccountCount(9999);

        //只创建租户和管理员角色
         return success(tenantService.createTenant(createReqVO));

        //创建基础角色及租户管理员
        //tenantService.createTenant(createReqVO);
        //TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(114L);
        //return success(tenantService.createBasicsRole(tenantPackage));
    }


    @PostMapping("/updateTenantByPortal")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> updateTenantByPortal(@RequestBody IdsVo idsVo) {
        TenantUpdateReqVO updateReqVO = new TenantUpdateReqVO();
        TenantDO tenantDO = tenantService.getTenantByName(idsVo.getTenantName());
        if (idsVo.getExpireTime() == null) {
            updateReqVO.setExpireTime(tenantDO.getExpireTime());
        } else {
            updateReqVO.setExpireTime(DateUtil.format(idsVo.getExpireTime(),"yyyy-MM-dd HH:mm:ss"));
        }
        updateReqVO.setId(tenantDO.getId());
        updateReqVO.setName(tenantDO.getName());
        updateReqVO.setContactName(tenantDO.getContactName());
        updateReqVO.setStatus(tenantDO.getStatus());
        updateReqVO.setPackageId(tenantDO.getPackageId());
        updateReqVO.setAccountCount(tenantDO.getAccountCount());
        tenantService.updateTenant(updateReqVO);
        return success(true);
    }


    @PostMapping("/deleteTenantByPortal")
    @PermitAll
    @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
    public CommonResult<Boolean> deleteTenantByPortal(@RequestBody IdsVo idsVo) {
        TenantDO tenantDO = tenantService.getTenantByName(idsVo.getTenantName());
        tenantService.deleteTenant(tenantDO.getId());
        return success(true);
    }

}
